Skip to content

Runtime-async sequence improvements: allow awaits in try/with and guard pending moves - #20655

Open
majocha wants to merge 15 commits into
dotnet:mainfrom
majocha:runtime-async-seq-trywith
Open

majocha wants to merge 15 commits into
dotnet:mainfrom
majocha:runtime-async-seq-trywith

Conversation

@majocha

@majocha majocha commented Sep 28, 2026 •

Copy link
Copy Markdown
Contributor

Description

  • Runtime-async sequence producers can now suspend inside try/with: in the protected body, in when filters, and in
    handlers. The source is disposed before the handler runs.
// low level
let source =
    __runtimeAsyncSequence (fun () -> seq {
        try
            yield 1
            Task.Delay 200 |> AsyncHelpers.Await
            failwith "expected"
        with _ ->
            Task.Delay 200 |> AsyncHelpers.Await
            yield 2
    })

// using a builder
let builderSource =
            asyncSeq2 {
                try
                    yield 1
                    do! Task.Delay 10
                    failwith "expected"
                with _ ->
                    do! Task.Delay 10
                    yield 2
            }


runtimeTask {
    for i in source do
        printfn $"step {i}"
}

  • A second MoveNextAsync or a DisposeAsync while a move is still pending now throws InvalidOperationException instead of corrupting the state machine.
  • The component tests now use updated async2, runtimeTask, and asyncSeq2 sample builders. asyncSeq2 shows stack-safe yield! and a YieldFromFinal tail handoff built on the compiler feature.

Fixes # (issue, if applicable)

Checklist

  • Test cases added
  • Performance benchmarks added in case of performance changes
  • Release notes entry updated

majocha and others added 4 commits September 28, 2026 14:04
Lower producer try/with to RuntimeAsyncSequenceHelpers.EnumerateTryWith, a new
FSharp.Core compiler-services helper. The source, filter and handler become
independent runtime-async iterators driven with the enumeration's cancellation
token, so awaits are allowed in the protected body, filters and handlers. The
source is disposed before the handler runs.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Generated sequence types no longer re-implement IAsyncEnumerator directly, so
interface calls dispatch through GeneratedRuntimeAsyncSequenceBase. The base
rejects a second MoveNextAsync, or a DisposeAsync, while a move is pending. The
generated MoveNextAsync releases the guard from a finally block through
CompleteMoveNext, before its result completes.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Replace the runtime-async test fixtures' sample builders with copies of the
reference async2 (cancellable), runtimeTask and asyncSeq2 builders and their
test suites. The producer/consumer asyncSeq builder and its tests are removed;
asyncSeq2 covers async sequences through __runtimeAsyncSequence, including
stack-safe yield! and YieldFromFinal handoff. Tests share the builders through
withSampleBuilders.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@github-actions

github-actions Bot commented Sep 28, 2026 •

Copy link
Copy Markdown
Contributor

✅ Release notes checked


✅ Found changes and release notes in following paths:

Change path Release notes path Description
`src/FSharp.Core` docs/release-notes/.FSharp.Core/11.0.200.md
`src/Compiler` docs/release-notes/.FSharp.Compiler.Service/11.0.200.md

@majocha majocha changed the title Runtime-async improvements: allow awaits in try/with and guard pending moves in async sequences Runtime-async sequence improvements: allow awaits in try/with and guard pending moves Sep 28, 2026
majocha and others added 5 commits September 28, 2026 14:47
Bring back RuntimeAsyncEnumerableTests (try/with, tail recursion, pull-driven
and concurrent MoveNext coverage), now running on asyncSeq2. asyncSeq2 accepts
F# Async as a cold source that receives the enumeration token. New builder
tests cover cancellation, unmatched exceptions escaping try/with unwrapped, and
deep non-tail yield!. The MergeSources overlap test checks start order with
gated awaitables instead of elapsed time.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
…ders in their folder

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Replace the FSharp.Core EnumerateTryWith helper with in-machine handling:
- MoveNextAsync catches faults and re-enters the jump table, which routes
  each state to its innermost pending finally or handler, so bodies,
  guards, handlers and finally blocks can all await.
- DisposeAsync sets a disposing flag and runs MoveNextAsync once more to
  execute pending finally blocks, skipping handlers.
- GeneratedRuntimeAsyncSequenceBase implements DisposeAsync; generated
  types override a sync Close instead.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Remove the Seq.collect fallback. Non-delayed sources are enumerated inside
the protected region, and filters that the handler does not already encode
run before the handler.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@majocha
majocha marked this pull request as ready for review September 28, 2026 20:11
@majocha
majocha requested a review from a team as a code owner September 28, 2026 20:11
@github-actions github-actions Bot added the ⚠️ Affects-Compiler-Output Tooling check: PR touches IL emission or codegen label Sep 28, 2026
@github-actions

This comment has been minimized.

@github-actions

Copy link
Copy Markdown
Contributor

🔍 Tooling Safety Check — Affects-Compiler-Output
Affects-Compiler-Output: Changes compiler-emitted member signatures.

Generated by PR Tooling Safety Check · gpt56 2.5M · ◷

@T-Gro T-Gro left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 🕵️ AI review — verify independently.

Comment thread src/Compiler/Optimize/LowerSequences.fs
Comment thread tests/FSharp.Compiler.ComponentTests/Language/RuntimeAsync/Async2Builder.fs Outdated
@T-Gro
T-Gro self-requested a review September 29, 2026 10:00
@T-Gro T-Gro added AI-reviewed PR reviewed by AI review council Needs-Servicing labels Sep 29, 2026

@T-Gro T-Gro left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 🕵️ Re-reviewed all recent changes as of 27a4dca; LGTM

@T-Gro

T-Gro commented Oct 6, 2026

Copy link
Copy Markdown
Member

@majocha :

I will want to backport some bug fixes (also w.r.t to runtime async) to net11 GA.
I think this PR does not meet the servicing bar and will have to wait for 11.0.200 (later 2027 release) - unless it fixes a real regression.

Since this touches many relevant lines, I will delay merging this one until the fixes are ported (to make them portable), and only merge after.

WDYT?

@majocha

majocha commented Oct 6, 2026

Copy link
Copy Markdown
Contributor Author

Yes, I have no objections. The whole thing is very much a preview feature and my main concern is to keep it as self-contained as possible and not to break something unrelated.

@T-Gro T-Gro left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 🕵️ Re-reviewed all recent changes as of 807c328; LGTM

@T-Gro T-Gro left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 🕵️ Re-reviewed all recent changes as of 0499ce3; LGTM

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

⚠️ Affects-Compiler-Output Tooling check: PR touches IL emission or codegen AI-reviewed PR reviewed by AI review council

Projects

Status: New

Development

Successfully merging this pull request may close these issues.

2 participants